# -*- coding: utf-8 -*

import datastore
import geohelper
import search
import distance

class LittleTravelState:
    def __init__(self, howToGetHere, spentMoney, spentTime, curStop, startStop, lineType, lineNo):
        self.howToGetHere = howToGetHere
        self.spentMoney = spentMoney
        self.spentTime = spentTime

        # initial state : curStop=None, startStop=None, lineType= None, lineNo=None
        self.curStop = curStop
        self.startStop = startStop
        self.lineType = lineType
        self.lineNo = lineNo

    def __eq__(self, other):
        return self.curStop.key() == other.curStop.key()

    def __repr__(self):
        res = '(%s: %d, %d - ' % (self.howToGetHere, self.spentMoney, self.spentTime)
        if self.curStop:
            res += self.curStop.name.encode('utf-8') + ', '
        else:
            res += 'None, '
        if self.startStop:
            res += self.startStop.name.encode('utf-8') + ', '
        else:
            res += 'None, '
        if self.lineType:
            res += self.lineType
        else:
            res += 'None, '
        if self.lineNo:
            res += self.lineNo.name.encode('utf-8') + ')'
        else:
            res += 'None)'
        return res

class LittleTravelAction:
    def __init__(self, stateBefore, stateAfter):
        self.stateBefore = stateBefore
        self.stateAfter = stateAfter

    def __repr__(self):
        return str(self.stateBefore) + ' ' + str(self.stateAfter)

class LittleTravelMgr:
    def __init__(self, startSpot, goalSpot):
        self.startSpot = startSpot
        self.goalSpot = goalSpot
        self.goalStops = geohelper.getNearbyStops(self.goalSpot.location)
        if geohelper.isWalkable(startSpot.location, goalSpot.location):
            self.goalStops.append(self.startSpot)

    def getStartState(self):
        return LittleTravelState(howToGetHere='Initial',
                                 spentMoney=0,
                                 spentTime=0,
                                 curStop=self.startSpot,
                                 startStop=None,
                                 lineType=None,
                                 lineNo=None)

    def isGoalState(self, state):
        return state.curStop.key() == self.goalSpot.key()

    def getSuccessors(self, state):
        succ = []
        
        foundGoal = False
        for stop in self.goalStops:
            if stop.key() == state.curStop.key():
                foundGoal = True
                break

        if state.howToGetHere == 'Initial':
            #stops available from START
            nextNodes = geohelper.getNearbyStops(self.startSpot.location)
            if foundGoal:
                nextNodes.append(self.goalSpot)
            for nextNode in nextNodes:
                nextState = LittleTravelState(howToGetHere='Walking',
                                              spentMoney=0,
                                              spentTime=geohelper.getWalkingTime(self.startSpot.location, nextNode.location),
                                              curStop=nextNode,
                                              startStop=None,
                                              lineType=None,
                                              lineNo=None)
                action = LittleTravelAction(state, nextState)
                succ.append((nextState, action))

        elif state.howToGetHere == 'Walking':
            nextPlans = geohelper.getNextPlans(state.curStop)
            for nextPlan in nextPlans:
                nextState = LittleTravelState(howToGetHere='Vehicle',
                                              spentMoney=state.spentMoney,
                                              spentTime=state.spentTime + geohelper.getVehicleTime(state.curStop, nextPlan.stop),
                                              curStop=nextPlan.stopNext,
                                              startStop=state.curStop,
                                              lineType='Mrt',
                                              lineNo=nextPlan.line)
                action = LittleTravelAction(state, nextState)
                succ.append((nextState, action))
                
            if foundGoal:
                nextState = LittleTravelState(howToGetHere='Walking',
                                              spentMoney=state.spentMoney,
                                              spentTime=state.spentTime + geohelper.getWalkingTime(state.curStop.location, self.goalSpot.location),
                                              curStop=self.goalSpot,
                                              startStop=None,
                                              lineType=None,
                                              lineNo=None)
                action = LittleTravelAction(state, nextState)
                succ.append((nextState, action))

        elif state.howToGetHere == 'Vehicle':
            nextPlans = geohelper.getNextPlans(state.curStop)
            for nextPlan in nextPlans:
                if nextPlan.line == state.lineNo:
                    nextState = LittleTravelState(howToGetHere='Vehicle',
                                                  spentMoney=state.spentMoney,
                                                  spentTime=state.spentTime + geohelper.getVehicleTime(state.curStop, nextPlan.stop),
                                                  curStop=nextPlan.stopNext,
                                                  startStop=state.startStop,
                                                  lineType='Mrt',
                                                  lineNo=state.lineNo)
                else:
                    nextState = LittleTravelState(howToGetHere='Vehicle',
                                                  spentMoney=state.spentMoney + geohelper.getPrice(state.startStop, state.curStop, state.lineNo),
                                                  spentTime=state.spentTime + geohelper.getVehicleTime(state.curStop, nextPlan.stop),
                                                  curStop=nextPlan.stopNext,
                                                  startStop=state.curStop,
                                                  lineType='Mrt',
                                                  lineNo=nextPlan.line)
                action = LittleTravelAction(state, nextState)
                succ.append((nextState, action))

            walkingNodes = geohelper.getNearbyStops(state.curStop.location)
            if foundGoal:
                walkingNodes.append(self.goalSpot)
            for walkingNode in walkingNodes:
                nextState = LittleTravelState(howToGetHere='Walking',
                                              spentMoney=state.spentMoney + geohelper.getPrice(state.startStop, state.curStop, state.lineNo),
                                              spentTime=state.spentTime + geohelper.getWalkingTime(state.curStop.location, walkingNode.location),
                                              curStop=walkingNode,
                                              startStop=None,
                                              lineType=None,
                                              lineNo=None)
                action = LittleTravelAction(state, nextState)
                succ.append((nextState, action))

        else:
            raise Exception('no such "howToGetHere"')

        return succ

    def getCostOfActions(self, actions):
        if len(actions) == 0:
            return 0
        else:
            geo1 = actions[-1].stateAfter.curStop.location
            geo2 = self.goalSpot.location
            dist = distance.Distance().getDistance(geo1.lat, geo1.lon, geo2.lat, geo2.lon)
            return dist

class TravelPlanner:
    def __init__(self, spotKeys, ordered):
        self.ordered = ordered

        self.spots = []
        for spotKey in spotKeys:
            spot = datastore.HotSpot.get(spotKey)
            self.spots.append(spot)
        home = geohelper.getHomeSpot()
        self.spots = [home] + self.spots + [home]

        self.timeTables = []

        self.arrangeTravel()

    def arrangeTravel(self):
        # assume ordered
        self.ordered = True

        if self.ordered:
            for idxSpot in range(len(self.spots) - 1):
                littleMgr = LittleTravelMgr(startSpot=self.spots[idxSpot],
                                            goalSpot=self.spots[idxSpot + 1])
                newTimeTable = search.aStarSearch(littleMgr, search.geoHeuristic)
                self.timeTables.append(newTimeTable)
        else:
            pass # future work

    def getSpotsOrder(self):
        res = self.spots[1:-1]
        return res

    def makeTransRow(self, state):
        if state.howToGetHere == 'Initial':
            how = '出發'
        elif state.howToGetHere == 'Walking':
            how = '走路'
        elif state.howToGetHere == 'Vehicle':
            if state.lineType == 'Mrt':
                how = '捷運'
            elif state.lineType == 'Bus':
                how = '公車'
            else:
                raise Exception('no such "lineType"')
        else:
            raise Exception('no such "howToGetHere"')
            
        row = {'type': 'Trans',
               'how': how,
               'location': state.curStop.name}
        return row
    
    def getTimeTable(self):
        result = []
        for idxRow in range(len(self.timeTables)):
            stateLast = None
            table = self.timeTables[idxRow]
            for action in table:
                result.append(self.makeTransRow(action.stateBefore))
                stateLast = self.makeTransRow(action.stateAfter)
            result.append(stateLast)
            if idxRow != len(self.timeTables) - 1:
                row = {'type': 'Play',
                       'where': self.spots[idxRow + 1].name}
                result.append(row)
        return result
        
        '''
        res = []
        for idxRow in range(len(self.timeTables)):
            table = self.timeTables[idxRow]
            for action in table:
                type = 'Trans'
                if action.stateBefore.lineType != action.stateAfter.lineType or 
                if action.stateAfter.howToGetHere == 'Walking':
                    how = '走路'
                    begin = action.stateBefore.curStop.name
                    end = action.stateAfter.curStop.name
                    row = {'type': type, 
                           'how': how,
                           'from': begin,
                           'end': end}
                    res.append(row)
                if 
                else: # 'Vehicle'
                    
                    newLine = action.stateAfter.lineNo
                    if curLine == None:
                        curLine = newLine
                        continue
                    elif newLine == curLine:
                        continue
                    if action.stateAfter.lineType == 'Mrt':
                        how = '捷運'
                    else: # 'Bus'
                        how = '公車'
                    print action.stateBefore.curStop.name.encode('utf-8')
                    begin = action.stateBefore.startStop.name
                    end = action.stateBefore.curStop.name
                    curLine = newLine
                
            if idxRow != len(self.timeTables) - 1:
                row = {'type': 'Play',
                       'where': self.spots[idxRow],
                       'money': 500,
                       'time': 60}
                res.append(row)

        '''
        '''
        print '<pre>'
        for row in self.timeTable:
            print row
        print '</pre>'
        '''

        '''
        res = []
        mrt = ('mrt', '2012-01-04 20:00:00', '紅線', '台北車站', '公館', '$20', '00:30:00')
        bus = ('bus', '2012-01-04 20:30:00', '紅204', '公館', '景美', '$15', '00:20:00')
        res.append(mrt)
        res.append(bus)
        for spot in self.spots:
            res.append(('play', '2012-01-04 20:50:00', spot.name, '$200', '一個半小時'))
            res.append(mrt)
            res.append(bus)
        return res
        '''

